package xcanal

import (
	"crypto/tls"
	"math/rand"
	"net"
	"os"
	"time"

	"github.com/BurntSushi/toml"
	"github.com/pingcap/errors"
	"github.com/siddontang/go-log/log"
	"github.com/siddontang/go-log/loggers"
	"server/dbtools/xcanal/client"
	"server/dbtools/xcanal/mysql"
)

type DumpConfig struct {
	ExecutionPath string `toml:"mysqldump"`

	Tables  []string `toml:"tables"`
	TableDB string   `toml:"table_db"`

	Databases []string `toml:"dbs"`

	IgnoreTables []string `toml:"ignore_tables"`

	Where string `toml:"where"`

	DiscardErr bool `toml:"discard_err"`

	SkipMasterData bool `toml:"skip_master_data"`

	MaxAllowedPacketMB int `toml:"max_allowed_packet_mb"`

	Protocol string `toml:"protocol"`

	ExtraOptions []string `toml:"extra_options"`
}

type Config struct {
	Addr     string `toml:"addr"`
	User     string `toml:"user"`
	Password string `toml:"password"`

	Charset         string        `toml:"charset"`
	ServerID        uint32        `toml:"server_id"`
	Flavor          string        `toml:"flavor"`
	HeartbeatPeriod time.Duration `toml:"heartbeat_period"`
	ReadTimeout     time.Duration `toml:"read_timeout"`

	IncludeTableRegex []string `toml:"include_table_regex"`
	ExcludeTableRegex []string `toml:"exclude_table_regex"`

	DiscardNoMetaRowEvent bool `toml:"discard_no_meta_row_event"`

	Dump DumpConfig `toml:"dump"`

	UseDecimal bool `toml:"use_decimal"`
	ParseTime  bool `toml:"parse_time"`

	TimestampStringLocation *time.Location

	SemiSyncEnabled bool `toml:"semi_sync_enabled"`

	MaxReconnectAttempts int `toml:"max_reconnect_attempts"`

	DisableRetrySync bool `toml:"disable_retry_sync"`

	TLSConfig *tls.Config

	Logger loggers.Advanced

	Dialer client.Dialer
}

func NewConfigWithFile(name string) (*Config, error) {
	data, err := os.ReadFile(name)
	if err != nil {
		return nil, errors.Trace(err)
	}

	return NewConfig(string(data))
}

func NewConfig(data string) (*Config, error) {
	var c Config

	_, err := toml.Decode(data, &c)
	if err != nil {
		return nil, errors.Trace(err)
	}

	return &c, nil
}

func NewDefaultConfig() *Config {
	c := new(Config)

	c.Addr = "127.0.0.1:3306"
	c.User = "root"
	c.Password = ""

	c.Charset = mysql.DEFAULT_CHARSET
	c.ServerID = uint32(rand.New(rand.NewSource(time.Now().Unix())).Intn(1000)) + 1001

	c.Flavor = "mysql"

	c.Dump.ExecutionPath = "mysqldump"
	c.Dump.DiscardErr = true
	c.Dump.SkipMasterData = false

	streamHandler, _ := log.NewStreamHandler(os.Stdout)
	c.Logger = log.NewDefault(streamHandler)

	dialer := &net.Dialer{}
	c.Dialer = dialer.DialContext

	return c
}
